#指令存储器32寻址
#你好
#后续应修改为矩阵并同时修改访存形式
instr_mem = ['0'] * (65536)#(4294967296)

#数据存储器20位寻址
data_mem = ['0'] * (65536)

#32位寄存器共16个
register = ['0'] * (128)
r_list = ['r00', 'rax', 'rbx', 'rcx', 'rdx', 'rmx', 'rsp', 'rbp', 'rip', 'r09', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15']
#随存储器一同修改栈顶位置
register[48:56] = "00000F00"


ZF = 0 #是否为0
SF = 0 #是否小于0
OF = 0 #是否溢出


Edict={
      0:"halt",
      2:"非法",
}
class STAT_Error(Exception):
    def __init__(self, args):
        self.value=args
        
    def __str__(self):
        return repr(Edict[self.value])


fil = open('F:/learn/大三上/计算机体系结构/CAC/CAC1.0/test.txt','r')
instruction = fil.read()
instruction = instruction.replace('\n', '')
instr_pc_max = len(instruction)
for i in range(instr_pc_max):
    instr_mem[i] = instruction[i]
            


def fetch_decode(cur_pc):
    
    instr_cur = instr_mem[cur_pc*2:cur_pc*2+14]
    print(''.join(instr_cur))
    
    code0 = instr_cur[0]
    code1 = instr_cur[1]
    code2 = instr_cur[2]
    
    func = instr_cur[3]
    
    
    rA = instr_cur[4]
    rB = instr_cur[5]
    
    imm = int(''.join(instr_cur[6:]), 16)
    imm_shift = int(''.join(instr_cur[6:8]), 16)
    
    stat = 1
    next_instr_pc = cur_pc
    if code0 != '0':
        stat = 2
    else:
        if code1 == '0' and code2 == '0':
            if func == '0':
                stat = 0
            elif func == '1':
                next_instr_pc += 2
            else:
                stat = 2
        elif code1 == '1':
            if code2 in ['0', '2']:
                next_instr_pc += 3
            elif code2 in ['1', '3', '4', '5', '6']:
                next_instr_pc += 7
            else:
                stat = 2
        elif code1 == '2':
            if code2 == '0':
                next_instr_pc += 7
            elif code2 in ['1', '6']:
                next_instr_pc += 3
            else:
                stat = 2
        elif code1 == '3':
            if code2 in ['0']:
                next_instr_pc += 4
            else:
                stat = 2
        elif code1 == '4':
            if code2 == '1':
                next_instr_pc += 7
            elif code2 == '6':
                next_instr_pc += 3
            else:
                stat = 2
        else:
            stat = 2
                
    predict_pc = next_instr_pc
    if (code1 == '2' and code2 == '0') or (code1 == '4' and code2 == '0'):
        predict_pc = imm
        
    if code1 == '4' and code2 == '1':
        imm = next_instr_pc
        
    return cur_pc, stat, code0, code1, code2, func, rA, rB, imm, imm_shift, next_instr_pc

def access_register(pc, stat, code0, code1, code2, func, rA, rB, imm, imm_shift):
    
    dataA = 0
    dataB = 0
    
    if code1 == '1':
        if code2 in ['0', '1', '2', '3', '4', '6']:
            dataA = int(''.join(register[int(rA, 16)*8:int(rA, 16)*8+8]), 16)
            dataB = int(''.join(register[int(rB, 16)*8:int(rB, 16)*8+8]), 16)
    elif code1 == '2':
        if code2 in ['1', '6']:
            dataA = int(''.join(register[int(rA, 16)*8:int(rA, 16)*8+8]), 16)
            dataB = int(''.join(register[int(rB, 16)*8:int(rB, 16)*8+8]), 16)
    elif code1 == '3':
        if code2 in ['0']:
            dataB = int(''.join(register[int(rB, 16)*8:int(rB, 16)*8+8]), 16)
    elif code1 == '4':
        if code2 in ['1', '6']:
            dataB = int(''.join(register[int(rB, 16)*8:int(rB, 16)*8+8]), 16)
            
    dataA = int(''.join(register[int(rA, 16)*8:int(rA, 16)*8+8]), 16)
    dataB = int(''.join(register[int(rB, 16)*8:int(rB, 16)*8+8]), 16)
    

    
    return pc, stat, code0, code1, code2, func, rA, rB, imm, imm_shift, dataA, dataB

def execute(pc, stat, code0, code1, code2, func, rA, rB, imm, imm_shift, dataA, dataB):
    
    global ZF,OF,SF
    
    set_cc = False
    if code1 == '1' and code2 in ['2', '3']:
        set_cc = True
    
    ALUA = 0
    if code1 == '1':
        if code2 in ['0', '2']:
            ALUA = dataA
        elif code2 in ['1', '3', '4', '5', '6']:
            ALUA = imm
    elif code1 in ['2', '4']:
        if code2 == '1':
            ALUA = -4
        elif code2 == '6':
            ALUA = 4
    elif code1 == '3':
        if code2 in ['0']:
            ALUA = imm_shift
            
    ALUB = 0
    if code1 == '1':
        if code2 in ['1', '2', '3', '4', '6']:
            ALUB = dataB
    elif code1 == '2':
        if code2 in ['1', '6']:
            ALUB = dataB
    elif code1 == '3':
        if code2 in ['0']:
            ALUB = dataB
    elif code1 == '4':
        if code2 in ['1', '6']:
            ALUB = dataB
            print("ALUB : ", ALUB)
            
    ALUfunc = '0';
    if (code1 == '1' and (code2 in ['2', '3'])) or (code1 == '3' and code2 == '0'):
        ALUfunc = func
        
    val_ALU = 0
    if ALUfunc == '0':
        val_ALU = ALUB + ALUA
    elif ALUfunc == '1':
        val_ALU = ALUB - ALUA
    elif ALUfunc == '2':
        val_ALU = ALUB & ALUA
    elif ALUfunc == '3':
        val_ALU = ALUB ^ ALUA
    elif ALUfunc == 'E':
        val_ALU = ALUB << ALUA
        print(ALUB, "<<", ALUA, "=", val_ALU)
    elif ALUfunc == 'F':
        val_ALU = ALUB >> ALUA
        print(ALUB, ">>", ALUA, "=", val_ALU)
        

    if set_cc == True:
        if val_ALU == 0:
            ZF =1
        if val_ALU >= 2**32:
            OF = 1
            val_ALU = val_ALU - 2**32
        if val_ALU < 0: 
            OF = 1
            SF = 1
            val_ALU = val_ALU + 2**32
            
    Cnd = 0
    if func == '0':
        Cnd  = 1
    elif func == '1':
        if (SF^OF)|ZF:
            Cnd = 1        
    elif func == '2':
        if (SF^OF):
            Cnd = 1
    elif func == '3':
        if ZF:
            Cnd = 1
    elif func == '4':
        if not ZF:
            Cnd = 1
    elif func == '5':
        if not (SF^OF):
            Cnd = 1
    elif func == '6':
        if not (SF^OF)&~ZF:
            Cnd = 1
    
    
    #处理好rA和rB的值，在写回阶段只需判断是否为r0寄存器即可
    
    if (code1 in ['1', '2']) and code2 == '0':
        if Cnd == 1:
            rB = rB
        else:
            rB = '0'
    elif code1 == '1' and (code2 in ['2', '3', '4', '5']):
        rB = rB
    elif code1 == '2' and code2 in ['1', '6']:
        rB = rB
    elif code1 == '3' and code2 in ['0']:
        rB = rB
    elif code1 == '4' and code2 in ['1', '6']:
        rB = rB
    else:
        rB = '0'
    
    if (code1 in ['1', '2']) and code2 == '6':
        rA = rA
    elif code1 == '1' and code2 == '4':
        rA = rA
    else:
        rA = '0'
        
    return pc, stat, code0, code1, code2, func, rA, rB, imm, dataA, dataB, Cnd, val_ALU

def access_memory(pc, stat, code0, code1, code2, func, rA, rB, imm, dataA, dataB, Cnd, val_ALU):
    
    
    if code1 in ['1', '2'] :
        if code2 == '1':
            data_mem[val_ALU*2:val_ALU*2+8] = '0x{:08X}'.format(dataA)[2:10]
        
    val_mem = 0
    if code1 == '1' and code2 == '6': #mrmov
        val_mem = int(''.join(data_mem[val_ALU*2:val_ALU*2+8]), 16)
    elif code1 == '2' and code2 == '6': #pull
        val_mem = int(''.join(data_mem[dataB*2:dataB*2+8]), 16)
    elif code1  == '1' and code2 == '4':
        if func == 'A':
            val_mem = int(''.join(data_mem[val_ALU*2:val_ALU*2+2]), 16)
        elif func == 'B':
            val_mem = int(''.join(data_mem[val_ALU*2:val_ALU*2+4]), 16)
        elif func == 'C':
            val_mem = int(''.join(data_mem[val_ALU*2:val_ALU*2+8]), 16)
        elif func in ['1', '2', '3', '4', '5', '6', '7', '8', '9']:
            ans = 0
            length = int(func)
            for i in range(length):
                num = int(data_mem[val_ALU*2+i], 16)
                if num > 9:
                    print("Wrong decimal code")
                    return
                else:
                    ans += (num*10**(length-1-i))
            val_mem = ans
    elif code1 == '4':
        if code2 == '2':
            val_mem = int(''.join(data_mem[dataB*2:dataB*2+8]), 16)
        elif code2 == '1':
            data_mem[val_ALU*2:val_ALU*2+8] = '0x{:08X}'.format(imm)[2:10]
            
    return stat, code0, code1, code2, func, rA, rB, imm, dataA, dataB, Cnd, val_ALU, val_mem

def write_back(stat, code0, code1, code2, func, rA, rB, imm, dataA, dataB, Cnd, val_ALU, val_mem):
    
    if rB != '0':
        register[int(rB, 16)*8:int(rB, 16)*8+8] = '0x{:08X}'.format(val_ALU)[2:10]
        print(f"Write to {rB} : {'0x{:08X}'.format(val_ALU)[2:10]}", code1, code2)
    
    if rA != '0':
        register[int(rA, 16)*8:int(rA, 16)*8+8] = '0x{:08X}'.format(val_mem)[2:10]
        print(f"Write to {rA} : {'0x{:08X}'.format(val_mem)[2:10]}")
        
    return stat, code0, code1, code2, func, imm, val_mem, Cnd

def select_pc(stat, code0, code1, code2, func, imm, next_instr_pc, val_mem, Cnd):
    
    pc = next_instr_pc
    if code1 == '2' and code2 == '0':
        if Cnd == 1:
            print("jump")
            pc = imm
    elif code1 == '4':
        if code2 == '6':
            pc = val_mem
        elif code2 == '1':
            print("call jump to : ", imm)
            pc = imm
    
    return pc



def i():
    print(''.join(instr_mem))
    
def d():
    print(''.join(data_mem))

def r():
    for i in range(len(r_list)):
        print(f"{r_list[i]} : {int(''.join(register[i*8:i*8+8]), 16)}")








#第一条指令必须是nop 总指令条数必须大于等于6
first_pc = 0
second_pc = 2

#均表示为该部分的输入值
#next_instr_pc应从FD直接传送给Sp阶段，应删去其他部件关于该数据的传送
statSP, code0SP, code1SP, code2SP, funcSP, immSP, next_instr_pcSP, val_memSP, CndSP = '0', '0', '0', '0', '0', 0, 0, 0, 0
statWB, code0WB, code1WB, code2WB, funcWB, rAWB, rBWB, immWB, next_instr_pcWB, dataAWB, dataBWB, CndWB, val_ALUWB, val_memWB = '0', '0', '0', '0', '0', '0', '0', 0, 0, 0, 0, 0, 0, 0
pcAM, statAM, code0AM, code1AM, code2AM, funcAM, rAAM, rBAM, immAM, next_instr_pcAM, dataAAM, dataBAM, CndAM, val_ALUAM, val_memAM = 0, '0', '0', '0', '0', '0', '0', '0', 0, 0, 0, 0, 0, 0, 0
pcEX, statEX, code0EX, code1EX, code2EX, funcEX, rAEX, rBEX, immEX, imm_shEX, next_instr_pcEX, dataAEX, dataBEX = 0, '0', '0', '0', '0', '0', '0', '0', 0, 0, 0, 0, 0
pcAR, statAR, code0AR, code1AR, code2AR, funcAR, rAAR, rBAR, immAR, imm_shAR, next_instr_pcAR = 0, '0', '0', '0', '0', '0', '0', '0', 0, 0, 0
cur_pc = 0

#clock one
cur_pc = select_pc(statSP, code0SP, code1SP, code2SP, funcSP, immSP, first_pc, val_memSP, CndSP)

#clock two
pcAR, statAR, code0AR, code1AR, code2AR, funcAR, rAAR, rBAR, immAR, imm_shAR, next_instr_pcAR = fetch_decode(cur_pc)
cur_pc = select_pc(statSP, code0SP, code1SP, code2SP, funcSP, immSP, second_pc, val_memSP, CndSP)

#colck three
pcEX, statEX, code0EX, code1EX, code2EX, funcEX, rAEX, rBEX, immEX, imm_shEX, dataAEX, dataBEX = access_register(pcAR, statAR, code0AR, code1AR, code2AR, funcAR, rAAR, rBAR, immAR, imm_shAR)
pcAR, statAR, code0AR, code1AR, code2AR, funcAR, rAAR, rBAR, immAR, imm_shAR, next_instr_pcAR = fetch_decode(cur_pc)
cur_pc = select_pc(statSP, code0SP, code1SP, code2SP, funcSP, immSP, next_instr_pcAR, val_memSP, CndSP)

#clock four
pcAM, statAM, code0AM, code1AM, code2AM, funcAM, rAAM, rBAM, immAM, dataAAM, dataBAM, CndAM, val_ALUAM = execute(pcEX, statEX, code0EX, code1EX, code2EX, funcEX, rAEX, rBEX, immEX, imm_shEX, dataAEX, dataBEX)
pcEX, statEX, code0EX, code1EX, code2EX, funcEX, rAEX, rBEX, immEX, imm_shEX, dataAEX, dataBEX = access_register(pcAR, statAR, code0AR, code1AR, code2AR, funcAR, rAAR, rBAR, immAR, imm_shAR)
pcAR, statAR, code0AR, code1AR, code2AR, funcAR, rAAR, rBAR, immAR, imm_shAR, next_instr_pcAR = fetch_decode(cur_pc)
cur_pc = select_pc(statSP, code0SP, code1SP, code2SP, funcSP, immSP, next_instr_pcAR, val_memSP, CndSP)

#clock five
statWB, code0WB, code1WB, code2WB, funcWB, rAWB, rBWB, immWB, dataAWB, dataBWB, CndWB, val_ALUWB, val_memWB = access_memory(pcAM, statAM, code0AM, code1AM, code2AM, funcAM, rAAM, rBAM, immAM, dataAAM, dataBAM, CndAM, val_ALUAM)
pcAM, statAM, code0AM, code1AM, code2AM, funcAM, rAAM, rBAM, immAM, dataAAM, dataBAM, CndAM, val_ALUAM = execute(pcEX, statEX, code0EX, code1EX, code2EX, funcEX, rAEX, rBEX, immEX, imm_shEX, dataAEX, dataBEX)
pcEX, statEX, code0EX, code1EX, code2EX, funcEX, rAEX, rBEX, immEX, imm_shEX, dataAEX, dataBEX = access_register(pcAR, statAR, code0AR, code1AR, code2AR, funcAR, rAAR, rBAR, immAR, imm_shAR)
pcAR, statAR, code0AR, code1AR, code2AR, funcAR, rAAR, rBAR, immAR, imm_shAR, next_instr_pcAR = fetch_decode(cur_pc)
cur_pc = select_pc(statSP, code0SP, code1SP, code2SP, funcSP, immSP, next_instr_pcAR, val_memSP, CndSP)

while(True):
    
    statSP, code0SP, code1SP, code2SP, funcSP, immSP, val_memSP, CndSP = write_back(statWB, code0WB, code1WB, code2WB, funcWB, rAWB, rBWB, immWB, dataAWB, dataBWB, CndWB, val_ALUWB, val_memWB)
    statWB, code0WB, code1WB, code2WB, funcWB, rAWB, rBWB, immWB, dataAWB, dataBWB, CndWB, val_ALUWB, val_memWB = access_memory(pcAM, statAM, code0AM, code1AM, code2AM, funcAM, rAAM, rBAM, immAM, dataAAM, dataBAM, CndAM, val_ALUAM)
    pcAM, statAM, code0AM, code1AM, code2AM, funcAM, rAAM, rBAM, immAM, dataAAM, dataBAM, CndAM, val_ALUAM = execute(pcEX, statEX, code0EX, code1EX, code2EX, funcEX, rAEX, rBEX, immEX, imm_shEX, dataAEX, dataBEX)
    pcEX, statEX, code0EX, code1EX, code2EX, funcEX, rAEX, rBEX, immEX, imm_shEX, dataAEX, dataBEX = access_register(pcAR, statAR, code0AR, code1AR, code2AR, funcAR, rAAR, rBAR, immAR, imm_shAR)
    pcAR, statAR, code0AR, code1AR, code2AR, funcAR, rAAR, rBAR, immAR, imm_shAR, next_instr_pcAR = fetch_decode(cur_pc)
    cur_pc = select_pc(statSP, code0SP, code1SP, code2SP, funcSP, immSP, next_instr_pcAR, val_memSP, CndSP)
    
    try:
        if statAR == 0:
            raise STAT_Error(0)
        elif statAR == 2:
            raise STAT_Error(2)
    except STAT_Error as err:
        print(f"current_pc : {cur_pc}\nlast_pc : {err}")
        break
        
        






fil.close()




#存储器应改为二维数组表示，以支持32位绝对寻址，相应的，寻址方式也要同步更新
#目前仅支持无符号整型数，应进一步更新为支持补码形式
#指令集正确性验证未完成
    #01编号 正确
    #02编码 正确
    #03编码 正确
    #04编码 正确
#异常情况仅FD阶段完整考虑，其他阶段均未添加











